package app

import (
	"fmt"
	"html/template"
	"math/rand"
	"net"
	"net/http"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"
)

type WaitGroupWrapper struct {
	sync.WaitGroup
}

func (w *WaitGroupWrapper) Wrap(cb func()) {
	w.Add(1)
	go func() {
		cb()
		w.Done()
	}()
}

/**
获取客户端真实IP
*/
func ClientIP(r *http.Request) string {
	xForwardedFor := r.Header.Get("X-Forwarded-For")
	ip := strings.TrimSpace(strings.Split(xForwardedFor, ",")[0])
	if ip != "" {
		return ip
	}

	ip = strings.TrimSpace(r.Header.Get("X-Real-Ip"))
	if ip != "" {
		return ip
	}

	if ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); err == nil {
		return ip
	}

	return ""
}

/**
InStringArray
*/
func InStringArray(val string, arr []string) bool {
	for _, v := range arr {
		if val == v {
			return true
		}
	}
	return false
}

var SystemLogLevel = []string{
	"system",
	"tcpDebug",
	"debug",
	"info",
	"error",
	"panic",
}

/**
P("message-string")
P("message-string", "info")
P("message-string", "message-string2", "panic")
*/
func P(param ...string) {
	n := len(param)
	now := time.Now().Format(time.StampMicro)

	var (
		level string
		msg   string
	)

	if n == 1 {
		level = "info"
		msg = param[0]
	} else {
		level = param[n-1]
		if InStringArray(level, SystemLogLevel) {
			msg = strings.Join(param[0:n-1], "  ||  ")
		} else {
			level = "info"
			msg = strings.Join(param, "  ||  ")
		}
	}

	if InStringArray(level, []string{"error", "panic"}) {
		_, file, line, ok := runtime.Caller(1)
		if ok {
			msg += fmt.Sprintf("  ||  [error in file '%s' on line %d]", file, line)
		}
	}

	fmt.Printf("[%s][%8s] %s\r\n", now, level, msg)
	if level == "panic" {
		os.Exit(1)
	}
}

/**
获取随机字符串
*/
func GetRandomString(l int) string {
	str := "0123456789abcdefghijklmnopqrstuvwxyz"
	bytes := []byte(str)
	result := []byte{}
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < l; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

//模板页面使用的函数列表
var FuncMap = template.FuncMap{}

/**
目录信息
*/
func PathExists(path string) (res bool, err error, fileInfo os.FileInfo) {
	fileInfo, err = os.Stat(path)
	if err == nil {
		return true, nil, fileInfo
	}
	if os.IsNotExist(err) {
		return false, nil, fileInfo
	}
	return false, err, fileInfo
}

/**
strInArray
*/
func strInArray(str string, arr []string) bool {
	for _, k := range arr {
		if str == k {
			return true
		}
	}
	return false
}
